Lær hvordan du organiserer dine Django REST Framework API'er effektivt ved hjælp af ViewSets. Denne guide dækker alt fra grundlæggende brug til avanceret tilpasning.
Django REST Framework ViewSets: Mestring af API Endpoint-organisation
I moderne webudvikling er det afgørende at bygge robuste og velstrukturerede API'er. Django REST Framework (DRF) er et kraftfuldt værktøjssæt til at skabe RESTful API'er med Django. Selvom DRF tilbyder forskellige værktøjer til at skabe API-endpoints, giver ViewSets en elegant måde at organisere relaterede visninger i en enkelt klasse, hvilket fører til renere og mere vedligeholdelig kode. Denne omfattende guide vil udforske ViewSets i detaljer og dække deres fordele, brug og avancerede tilpasningsteknikker.
Hvad er ViewSets?
Et ViewSet er en klassebaseret View, der giver implementeringer til standardoperationer, såsom list
, create
, retrieve
, update
og destroy
. I stedet for at definere separate visninger for hver operation, kombinerer et ViewSet dem i en enkelt klasse, hvilket forenkler API-strukturen og reducerer kode-duplikering. ViewSets er især nyttige, når du arbejder med modelbaserede API'er, hvor disse standardoperationer ofte er påkrævet. Tænk på et ViewSet som en logisk gruppering af operationer på en specifik ressource.
Fordele ved at bruge ViewSets
- Kode Genanvendelighed: ViewSets fremmer kode genanvendelse ved at indkapsle almindelig API-logik i en enkelt klasse. Dette reducerer redundans og gør koden lettere at vedligeholde.
- Forenklet Routing: ViewSets forenkler routing ved at gruppere relaterede visninger under et enkelt URL-præfiks. Dette resulterer i en renere og mere organiseret URL-struktur.
- Reduceret Boilerplate: ViewSets reducerer boilerplate-kode ved at levere standardimplementeringer til almindelige API-operationer. Dette giver udviklere mulighed for at fokusere på at implementere brugerdefineret logik, der er specifik for deres applikation.
- Forbedret Læsbarhed: ViewSets forbedrer kode-læsbarheden ved at organisere relaterede visninger i en enkelt klasse. Dette gør API-strukturen lettere at forstå og navigere.
- Konsistens: ViewSets hjælper med at sikre konsistens på tværs af API'en ved at håndhæve et standardsæt af operationer og konventioner. Dette gør API'en mere forudsigelig og lettere at bruge.
Grundlæggende Brug af ViewSets
Lad os starte med et simpelt eksempel på brug af ViewSets til at oprette en API til styring af produkter. Definer først en model:
# models.py
from django.db import models
class Product(models.Model):
name = models.CharField(max_length=255)
description = models.TextField()
price = models.DecimalField(max_digits=10, decimal_places=2)
def __str__(self):
return self.name
Definer derefter en serialisator for Product
modellen:
# serializers.py
from rest_framework import serializers
from .models import Product
class ProductSerializer(serializers.ModelSerializer):
class Meta:
model = Product
fields = '__all__'
Opret nu et ViewSet for Product
modellen:
# views.py
from rest_framework import viewsets
from .models import Product
from .serializers import ProductSerializer
class ProductViewSet(viewsets.ModelViewSet):
queryset = Product.objects.all()
serializer_class = ProductSerializer
Konfigurer til sidst URL-routing:
# urls.py
from django.urls import path, include
from rest_framework import routers
from . import views
router = routers.DefaultRouter()
router.register(r'products', views.ProductViewSet)
urlpatterns = [
path('', include(router.urls)),
]
Denne konfiguration genererer automatisk følgende API-endpoints:
/products/
(GET: list, POST: create)/products/{id}/
(GET: retrieve, PUT: update, PATCH: partial_update, DELETE: destroy)
ModelViewSet
giver standardimplementeringer til alle standard CRUD-operationer. queryset
attributten specificerer det sæt objekter, som ViewSet skal operere på, og serializer_class
attributten specificerer den serialisator, der skal bruges til serialisering og deserialisering af data.
Typer af ViewSets
DRF leverer flere indbyggede ViewSet-klasser, der imødekommer forskellige brugsscenarier:
ViewSet
: Basisklassen for alle ViewSets. Det giver den grundlæggende infrastruktur til håndtering af anmodninger og svar.ReadOnlyModelViewSet
: Et ViewSet, der giver skrivebeskyttede operationer (list
ogretrieve
). Dette er nyttigt til API'er, der kun tillader datahentning.ModelViewSet
: Et ViewSet, der giver alle standard CRUD-operationer (list
,create
,retrieve
,update
ogdestroy
). Dette er det mest almindeligt anvendte ViewSet til modelbaserede API'er.GenericViewSet
: Et ViewSet, der giver en generisk implementering til almindelige API-operationer. Dette kan bruges som en basisklasse til at oprette brugerdefinerede ViewSets.
Valg af det rigtige ViewSet afhænger af de specifikke krav til din API. Hvis du kun har brug for skrivebeskyttede operationer, skal du bruge ReadOnlyModelViewSet
. Hvis du har brug for alle standard CRUD-operationer, skal du bruge ModelViewSet
. Hvis du har brug for mere kontrol over API-opførslen, kan du oprette et brugerdefineret ViewSet ved at arve fra GenericViewSet
eller ViewSet
.
Tilpasning af ViewSets
Selvom de indbyggede ViewSets giver en bekvem måde at oprette API'er, kan det være nødvendigt at tilpasse deres adfærd for at opfylde specifikke krav. DRF giver flere måder at tilpasse ViewSets på, herunder tilsidesættelse af metoder, tilføjelse af brugerdefinerede handlinger og brug af brugerdefinerede serialisatorer.
Tilsidesættelse af Metoder
Du kan tilsidesætte standardimplementeringerne af standard API-operationerne ved at definere metoder med de samme navne i din ViewSet-klasse. Du kan for eksempel tilsidesætte create
metoden for at tilføje brugerdefineret logik før eller efter oprettelse af et nyt objekt:
# views.py
from rest_framework import viewsets
from .models import Product
from .serializers import ProductSerializer
from rest_framework.response import Response
from rest_framework import status
class ProductViewSet(viewsets.ModelViewSet):
queryset = Product.objects.all()
serializer_class = ProductSerializer
def create(self, request, *args, **kwargs):
serializer = self.get_serializer(data=request.data)
serializer.is_valid(raise_exception=True)
# Tilføj brugerdefineret logik her før oprettelse af objektet
self.perform_create(serializer)
headers = self.get_success_headers(serializer.data)
return Response(serializer.data, status=status.HTTP_201_CREATED, headers=headers)
I dette eksempel tilsidesætter create
metoden standardimplementeringen og tilføjer brugerdefineret logik før oprettelse af objektet. perform_create
metoden kaldes for faktisk at oprette objektet, og svaret returneres med en 201 Created
statuskode.
Tilføjelse af Brugerdefinerede Handlinger
Du kan tilføje brugerdefinerede handlinger til dit ViewSet ved hjælp af @action
dekoratoren. Brugerdefinerede handlinger giver dig mulighed for at definere nye API-endpoints, der udfører specifikke operationer på de ressourcer, der administreres af ViewSet. Du kan for eksempel tilføje en handling for at markere et produkt som fremhævet:
# views.py
from rest_framework import viewsets
from .models import Product
from .serializers import ProductSerializer
from rest_framework.decorators import action
from rest_framework.response import Response
from rest_framework import status
class ProductViewSet(viewsets.ModelViewSet):
queryset = Product.objects.all()
serializer_class = ProductSerializer
@action(detail=True, methods=['post'])
def feature(self, request, pk=None):
product = self.get_object()
product.is_featured = True
product.save()
serializer = self.get_serializer(product)
return Response(serializer.data)
I dette eksempel definerer @action
dekoratoren et nyt API-endpoint /products/{id}/feature/
, der markerer et produkt som fremhævet. detail=True
argumentet indikerer, at handlingen opererer på en specifik instans af modellen. methods=['post']
argumentet specificerer, at handlingen kun accepterer POST-anmodninger.
Brug af Brugerdefinerede Serialisatorer
Du kan bruge brugerdefinerede serialisatorer til at tilpasse den måde, data serialiseres og deserialiseres af ViewSet. Dette er nyttigt, når du har brug for at håndtere komplekse datastrukturer eller udføre brugerdefineret validering. Du kan for eksempel bruge en brugerdefineret serialisator til at inkludere relaterede data i API-svaret:
# serializers.py
from rest_framework import serializers
from .models import Product, Category
class CategorySerializer(serializers.ModelSerializer):
class Meta:
model = Category
fields = ['id', 'name']
class ProductSerializer(serializers.ModelSerializer):
category = CategorySerializer(read_only=True)
class Meta:
model = Product
fields = '__all__'
# views.py
from rest_framework import viewsets
from .models import Product
from .serializers import ProductSerializer
class ProductViewSet(viewsets.ModelViewSet):
queryset = Product.objects.all()
serializer_class = ProductSerializer
I dette eksempel inkluderer ProductSerializer
en CategorySerializer
for at serialisere de relaterede kategori-data. Dette giver dig mulighed for at hente kategorioplysningerne sammen med produktoplysningerne i en enkelt API-anmodning.
Avancerede ViewSet-Teknikker
Ud over grundlæggende brug og tilpasning tilbyder ViewSets avancerede teknikker til at bygge sofistikerede API'er:
Filtrering
DRF giver kraftfulde filtreringsfunktioner, der giver dig mulighed for at filtrere forespørgslen baseret på anmodningsparametre. Du kan bruge filter_backends
attributten til at specificere de filtrerings-backends, der skal bruges. Du kan for eksempel bruge SearchFilter
til at give brugerne mulighed for at søge efter produkter efter navn eller beskrivelse:
# views.py
from rest_framework import viewsets
from .models import Product
from .serializers import ProductSerializer
from rest_framework import filters
class ProductViewSet(viewsets.ModelViewSet):
queryset = Product.objects.all()
serializer_class = ProductSerializer
filter_backends = [filters.SearchFilter]
search_fields = ['name', 'description']
I dette eksempel specificerer filter_backends
attributten, at SearchFilter
skal bruges. search_fields
attributten specificerer de felter, der skal søges i.
Paginering
DRF giver pagineringsfunktioner, der giver dig mulighed for at opdele forespørgslen i mindre sider. Dette er nyttigt, når du arbejder med store datasæt. Du kan bruge pagination_class
attributten til at specificere den pagineringsklasse, der skal bruges. Du kan for eksempel bruge PageNumberPagination
til at paginere resultaterne ved hjælp af sidetal:
# views.py
from rest_framework import viewsets
from .models import Product
from .serializers import ProductSerializer
from rest_framework.pagination import PageNumberPagination
class ProductViewSet(viewsets.ModelViewSet):
queryset = Product.objects.all()
serializer_class = ProductSerializer
pagination_class = PageNumberPagination
I dette eksempel specificerer pagination_class
attributten, at PageNumberPagination
skal bruges. Du kan også tilpasse pagineringsadfærden ved at oprette din egen pagineringsklasse.
Autentificering og Tilladelser
DRF giver fleksible autentificerings- og tilladelsesmekanismer, der giver dig mulighed for at kontrollere adgangen til dine API-endpoints. Du kan bruge authentication_classes
og permission_classes
attributterne til at specificere de autentificerings- og tilladelsesklasser, der skal bruges. Du kan for eksempel bruge TokenAuthentication
til at autentificere brugere ved hjælp af tokens og IsAuthenticated
tilladelsen til kun at tillade autentificerede brugere at få adgang til API'en:
# views.py
from rest_framework import viewsets
from .models import Product
from .serializers import ProductSerializer
from rest_framework.authentication import TokenAuthentication
from rest_framework.permissions import IsAuthenticated
class ProductViewSet(viewsets.ModelViewSet):
queryset = Product.objects.all()
serializer_class = ProductSerializer
authentication_classes = [TokenAuthentication]
permission_classes = [IsAuthenticated]
I dette eksempel specificerer authentication_classes
attributten, at TokenAuthentication
skal bruges, og permission_classes
attributten specificerer, at IsAuthenticated
tilladelsen skal bruges.
Bedste Praksis for Brug af ViewSets
For at sikre, at dine ViewSets er veldesignede og vedligeholdelige, skal du følge disse bedste praksisser:
- Hold ViewSets fokuserede: Hvert ViewSet skal være ansvarligt for at administrere en enkelt ressource eller et tæt relateret sæt af ressourcer. Undgå at oprette alt for komplekse ViewSets, der håndterer flere urelaterede operationer.
- Brug passende ViewSet-typer: Vælg den ViewSet-type, der bedst passer til kravene til din API. Brug
ReadOnlyModelViewSet
til skrivebeskyttede API'er,ModelViewSet
til CRUD API'er ogGenericViewSet
ellerViewSet
til brugerdefinerede API'er. - Følg RESTful principper: Design dine API-endpoints i henhold til RESTful principper. Brug standard HTTP-metoder (GET, POST, PUT, PATCH, DELETE) til at udføre operationer på ressourcer.
- Brug serialisatorer til datavalidering: Brug serialisatorer til at validere de data, der sendes til og modtages fra API'en. Dette hjælper med at sikre dataintegritet og forhindrer fejl.
- Implementer korrekt autentificering og tilladelser: Sikr dine API-endpoints ved at implementere korrekt autentificering og tilladelser. Dette hjælper med at beskytte dine data mod uautoriseret adgang.
- Skriv omfattende tests: Skriv omfattende tests for at sikre, at dine ViewSets fungerer korrekt. Dette hjælper med at forhindre regressioner og gør det lettere at vedligeholde koden.
Internationalisering (i18n) og Lokalisering (l10n) Overvejelser
Når du bygger API'er til et globalt publikum, er det vigtigt at overveje internationalisering (i18n) og lokalisering (l10n). ViewSets kan tilpasses til at understøtte flere sprog og regioner:
- Serialisatorfelter: Brug DRF's serialisatorfelter med passende oversættelsesfunktioner (f.eks.
gettext
fra Djangos i18n-framework) til at vise oversatte feltetiketter og hjælptekster. - Fejlmeddelelser: Sørg for, at fejlmeddelelser, der returneres af API'en, er oversat til brugerens foretrukne sprog.
- Dato- og Tidsformatering: Brug passende dato- og tidsformatering baseret på brugerens lokalitet. DRF giver muligheder for at tilpasse dato- og tidsformater.
- Valutaformatering: Formater valutaværdier i henhold til brugerens lokalitet. Overvej at bruge biblioteker som
babel
til valutaformatering. For eksempel kan en pris på 1234,56 i USD formateres som $1.234,56 i USA, men som 1.234,56 $ i nogle europæiske lande. - Tidszoner: Håndter tidszoner korrekt. Gem datoer og tidspunkter i UTC og konverter dem til brugerens lokale tidszone, når de vises.
For eksempel kan et produkt have en beskrivelse, der skal oversættes. Du ville bruge Djangos oversættelsessystem inden for serialisatoren:
# serializers.py
from rest_framework import serializers
from django.utils.translation import gettext_lazy as _
from .models import Product
class ProductSerializer(serializers.ModelSerializer):
description = serializers.CharField(help_text=_("Produktbeskrivelse"))
class Meta:
model = Product
fields = '__all__'
Og i dine skabeloner eller kode, der bruger denne serialisator, skal du sikre dig, at det korrekte sprog er aktiveret.
Eksempel: E-handels API med International Support
Forestil dig en e-handels API, der sælger produkter globalt. Product
modellen kan omfatte felter som name
, description
, price
og image
. API'en skal understøtte flere sprog og valutaer.
ViewSet ville håndtere de grundlæggende CRUD operationer for produkter. Serialisatorerne ville blive tilpasset til at understøtte oversættelse af produktnavn og beskrivelse. API'en ville også inkludere endpoints til at hente produkter efter kategori, filtrere produkter efter prisinterval og søge efter produkter efter nøgleord. Disse funktioner ville skulle overveje internationalisering, især omkring søgeord og produktbeskrivelser, der kan variere mellem sprog.
Eksempel URLS:
/en/products/
- Liste over produkter på engelsk/fr/products/
- Liste over produkter på fransk/en/products/?currency=USD
- Liste over produkter i USD/fr/products/123/?currency=EUR
- Detaljer om produkt 123 på fransk, prisen vises i EUR
Konklusion
Django REST Framework ViewSets giver en kraftfuld og elegant måde at organisere dine API-endpoints på. Ved at indkapsle relaterede visninger i en enkelt klasse fremmer ViewSets kode genanvendelse, forenkler routing og forbedrer kode læsbarheden. Med muligheden for at tilpasse ViewSets gennem tilsidesættelse af metoder, tilføjelse af brugerdefinerede handlinger og brug af brugerdefinerede serialisatorer, kan du skræddersy dem til at opfylde de specifikke krav til din API. Ved at følge de bedste fremgangsmåder, der er skitseret i denne guide, kan du sikre, at dine ViewSets er veldesignede, vedligeholdelige og skalerbare, hvilket resulterer i robuste og effektive API'er.
Husk at overveje internationalisering og lokalisering, når du bygger API'er til et globalt publikum. Tilpas dine ViewSets og serialisatorer til at understøtte flere sprog, valutaer og tidszoner for at give en problemfri oplevelse for brugere over hele verden.
Ved at mestre ViewSets kan du tage dine Django REST Framework færdigheder til næste niveau og bygge API'er, der er både kraftfulde og vedligeholdelige. Dette bidrager til software af høj kvalitet og en positiv brugeroplevelse for dit globale publikum.
Denne guide bør tjene som et solidt grundlag for at forstå og implementere ViewSets i dine Django REST Framework projekter. Fortsæt med at øve dig, eksperimentere og udforske DRF-dokumentationen for at blive en ægte ViewSet-mester!